#include <Arduino.h>
#include <cmath>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

#define LED_PIN 2

// WiFi配置
auto ssid = "TRTY_3F";
auto password = "89001888";

// NTP客户端设置
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000);

// 全局变量
unsigned long lastUpdateTime = 0;

float wind_lat = 0.0; //纬度
float wind_lon = 0.0; //经度

int wind_direction = 120; // 风向
float wind_speed = 20.0; // 风速 (m/s)

float water_lat = 0.0; //纬度
float water_lon = 0.0; //经度


// 计算NMEA校验和
String calculateChecksum(String sentence)
{
    int checksum = 0;
    for (int i = 1; i < sentence.length(); i++)
    {
        checksum ^= sentence.charAt(i);
    }
    char checksumStr[3];
    sprintf(checksumStr, "%02X", checksum);
    return {checksumStr};
}

// 格式化纬度 (ddmm.mmmm)
String formatLatitude(float lat)
{
    int degrees = (int)lat;
    float minutes = (lat - degrees) * 60;
    char latStr[12];
    sprintf(latStr, "%02d%07.4f", degrees, fabs(minutes));
    return {latStr};
}

// 格式化经度 (dddmm.mmmm)
String formatLongitude(float lon)
{
    int degrees = (int)lon;
    float minutes = (lon - degrees) * 60;
    char lonStr[13];
    sprintf(lonStr, "%03d%07.4f", degrees, fabs(minutes));
    return {lonStr};
}

// 生成WIMWV语句（风速风向）
String generateWIMWV(int windDir, char reference, float windSpeed)
{
    char sentence[100];
    char speedStr[8];
    dtostrf(windSpeed, 6, 2, speedStr);
    sprintf(sentence, "WIMWV,%03d,%c,%06.2f,M,A", windDir, reference, windSpeed);
    const String fullSentence = "$" + String(sentence);
    const String checksum = calculateChecksum(fullSentence);
    return fullSentence + "*" + checksum;
}

// 生成GPGGA语句（GPS定位）
String generateGPGGA(tm* ptm, float windLat, float windLon)
{
    char timeStr[12];
    sprintf(timeStr, "%02d%02d%02d.000", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

    const String latStr = formatLatitude(windLat);
    const String lonStr = formatLongitude(windLon);

    char sentence[200];
    sprintf(sentence, "GPGGA,%s,%s,N,%s,E,1,05,2.0,0.0,M,0.0,M,,0000", timeStr, latStr.c_str(), lonStr.c_str());

    const String full_sentence = "$" + String(sentence);
    const String checksum = calculateChecksum(full_sentence);
    return full_sentence + "*" + checksum;
}

// 生成PGILT语句（倾斜数据）
String generatePGILT()
{
    return "$PGILT,A,-04,D,+00,D,+1,TILT*36";
}

// 发送NMEA数据
void sendWind(tm* ptm)
{
    // 发送相对风数据
    String wimwvR = generateWIMWV(0.0, 'R', 0.0);

    // 发送真实风数据（模拟稍微不同的值）
    String wimwvT = generateWIMWV(wind_direction, 'T', wind_speed);

    // 发送GPS定位数据
    String gga = generateGPGGA(ptm, wind_lat, wind_lon);

    // 发送倾斜数据
    String pgilt = generatePGILT();

    String windData = wimwvR + "\r\n" + wimwvT + "\r\n" + gga + "\r\n" + pgilt;

    Serial1.println(windData);
    Serial.println(windData);
}


String generateGNRMC(tm* ptm, float waterLat, float waterLon, float gpsSpeed, float course)
{
    char timeStr[12];
    sprintf(timeStr, "%02d%02d%02d.000", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    char dateStr[10];
    sprintf(dateStr, "%02d%02d%02d", ptm->tm_mday, ptm->tm_mon + 1, (ptm->tm_year + 1900) % 100);

    const String latStr = formatLatitude(waterLat) + "0";
    const String lonStr = formatLongitude(waterLon) + "0";

    // 构建完整数据
    char nmeaStr[200];
    sprintf(nmeaStr, "GNRMC,%s,A,%s,N,%s,E,%.3f,%.2f,%s,,,A",
            timeStr, latStr.c_str(), lonStr.c_str(), gpsSpeed, course, dateStr);

    const String full_sentence = "$" + String(nmeaStr);
    const String checksum = calculateChecksum(full_sentence);
    return full_sentence + "*" + checksum;
}


void sendWater(tm* ptm)
{
    String gnrmc = generateGNRMC(ptm, water_lat, water_lon, 0, 0);
    Serial2.println(gnrmc);
    Serial.println(gnrmc);
}


void setup()
{
    // 初始化LED引脚
    pinMode(LED_PIN, OUTPUT);

    // 初始化串口
    Serial.begin(19200);

    // 风数据 UART1
    Serial1.begin(19200, SERIAL_8N1, 13, 12);
    // 流数据 UART2
    Serial2.begin(19200, SERIAL_8N1, 16, 17);

    // 连接WiFi
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi " + String(ssid));
    while (WiFiClass::status() != WL_CONNECTED)
    {
        delay(100);
        Serial.print(".");
    }
    Serial.println("\n " + String(ssid) + " WiFi connected " + WiFi.localIP().toString());

    // 初始化NTP客户端
    timeClient.begin();

    Serial.println("ESP32 wind and water sensor");
}

void loop()
{
    // 更新时间
    timeClient.update();
    // 获取详细时间信息
    unsigned long epochTime = timeClient.getEpochTime();
    tm* ptm = gmtime(reinterpret_cast<time_t*>(&epochTime));
    // 每秒发送一次
    if (epochTime - lastUpdateTime >= 1)
    {
        // 8字形轨迹计算 - 风传感器坐标
        float t = millis() / 10000; // 时间参数，调节速度
        float a = 0.1; // 经度变化幅度
        float b = 0.05; // 纬度变化幅度
        float center_lon = 122.047519; // 中心经度
        float center_lat = 31.060672; // 中心纬度

        wind_lon = center_lon + a * sin(t);
        wind_lat = center_lat + b * sin(t) * cos(t);

        sendWind(ptm);
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));

        delay(400);

        // 8字形轨迹计算 - 水流传感器坐标
        water_lon = center_lon + a * sin(t + PI); // 相位差形成对称8字
        water_lat = center_lat + b * sin(t + PI) * cos(t + PI);

        sendWater(ptm);
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));

        lastUpdateTime = epochTime;
    }
    delay(100);
}
